package com.itcanteen.medical.patient.service.impl;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.itcanteen.medical.common.constant.Constant;
import com.itcanteen.medical.common.exception.AdException;
import com.itcanteen.medical.patient.controller.PatientController;
import com.itcanteen.medical.patient.entity.Patient;
import com.itcanteen.medical.patient.mapper.PatientMapper;
import com.itcanteen.medical.patient.request.HealthTestRequest;
import com.itcanteen.medical.patient.request.SendCodeRequest;
import com.itcanteen.medical.patient.service.PatientService;
import com.itcanteen.medical.patient.util.OSSUploadUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

/**
 * 患者 业务层
 * @author 1804A-TeamOne
 * @date 2020-12-17 16:58
 */
@Service
public class PatientServiceImpl implements PatientService {

    @Resource
    private PatientMapper patientMapper;

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;

    @Value("${oss.utils.endpoint}")
    private String endpoint;

    @Value("${oss.utils.accessKeyId}")
    private String accessKeyId;

    @Value("${oss.utils.accessKeySecret}")
    private String accessKeySecret;

    @Value("${oss.utils.bucket}")
    private String bucket;

    /**
     * 健康基础分数
     */
    private static final Integer BASE_SCORE =36;

    /**
     * 密码MD5加密
     * @param password 密码
     * @return 加密后的密码
     * @throws AdException 统一异常
     */
    @Override
    public String encodeByMd5(String password) throws AdException {
        MessageDigest messageDigest;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new AdException(Constant.ErrorMsg.SYSTEM_BUSY);
        }
        BASE64Encoder base64Encoder = new BASE64Encoder();
        return base64Encoder.encode(messageDigest.digest(password.getBytes(StandardCharsets.UTF_8)));
    }

    /**
     * 根据手机号查询患者
     * @param phone 手机号
     * @return com.itcanteen.medical.patient.entity.Patient
     */
    @Override
    public Patient selectPatientByPhone(Long phone) {
        return patientMapper.selectByPhone(phone);
    }

    /**
     * 根据邮箱查询患者
     * @param email 邮箱
     * @return com.itcanteen.medical.patient.entity.Patient
     */
    @Override
    public Patient selectPatientByEmail(String email) {
        return patientMapper.selectByEmail(email);
    }

    /**
     * 根据用户名查询患者
     * @param username 用户名
     * @return com.itcanteen.medical.patient.entity.Patient
     */
    @Override
    public Patient selectPatientByUsername(String username) {
        return patientMapper.selectByUsername(username);
    }

    /**
     * 注册
     * @param registerRequest 注册请求类
     * @throws AdException 统一异常
     */
    @Override
    public void register(SendCodeRequest registerRequest) throws AdException {
        Patient patient = new Patient(
                registerRequest.getUsername(),
                encodeByMd5(registerRequest.getPassword())
        );
        if(registerRequest.getPhone()!=null){
            patient.setPhone(registerRequest.getPhone());
        }else if(registerRequest.getEmail()!=null){
            patient.setEmail(registerRequest.getEmail());
        }
        patientMapper.insert(patient);
    }

    /**
     * 改变账户状态
     * @param loginResp 登陆请求类
     */
    @Override
    public void changeStatus(Patient loginResp) {
        Patient patient = patientMapper.selectByPrimaryKey(loginResp.getId());
        patient.setStatus(-1);
        patient.setUpdateTime(new Date());
        patientMapper.updateByPrimaryKey(patient);
        patient = patientMapper.selectByPrimaryKey(loginResp.getId());
        changeStatusTimer(patient);
    }

    /**
     * 定时取消锁定
     * @param patient 需要修改状态的患者对象
     */
    public void changeStatusTimer(Patient patient) {
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("patient-change_status-%d").build();
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(5,threadFactory);
        scheduledThreadPoolExecutor.schedule(() -> {
            patient.setStatus(1);
            patient.setUpdateTime(new Date());
            patientMapper.updateByPrimaryKey(patient);
            redisTemplate.boundHashOps("loginFail"+ patient.getId()).delete("loginFail" + patient.getId());
        }, 5, TimeUnit.MINUTES);
    }

    /**
     * 根据id查询患者
     * @param id 患者id
     * @return com.itcanteen.medical.patient.entity.Patient
     */
    @Override
    public Patient findById(Integer id) {
        return patientMapper.selectByPrimaryKey(id);
    }

    /**
     * 更新密码
     * @param id 患者id
     * @param newPassword 新密码
     * @param session session
     * @throws AdException 统一异常
     */
    @Override
    public void updatePassword(Integer id, String newPassword, HttpSession session) throws AdException {
        Date now = new Date();
        String password = encodeByMd5(newPassword);
        patientMapper.updatePassword(id, password, now);
        //清空session中的用户信息
        if (session.getAttribute(PatientController.CURRENT_PATIENT) != null) {
            session.removeAttribute(PatientController.CURRENT_PATIENT);
        }
    }

    /**
     * 修改患者信息
     * @param patient 患者信息
     */
    @Override
    public void updatePatient(Patient patient) {
        patientMapper.updateByPrimaryKey(patient);
    }

    /**
     * 修改绑定手机号
     * @param id 患者id
     * @param phone 手机号
     * @param session session
     */
    @Override
    public void changeBindingPhone(Integer id, Long phone, HttpSession session) {
        Date now = new Date();
        patientMapper.updatePhone(id,phone,now);
        session.setAttribute(PatientController.CURRENT_PATIENT,findById(id));
    }

    /**
     * 修改绑定邮箱
     * @param id 患者id
     * @param email 邮箱
     * @param session session
     */
    @Override
    public void changeBindingEmail(Integer id, String email, HttpSession session) {
        Date now = new Date();
        patientMapper.updateEmail(id,email,now);
        session.setAttribute(PatientController.CURRENT_PATIENT,findById(id));
    }

    /**
     * 修改积分
     * @param id 患者id
     * @param integral 积分
     */
    @Override
    public void changeIntegral(Integer id, Integer integral) {
        Date now = new Date();
        patientMapper.updateIntegral(id,integral,now);
    }

    /**
     * 修改患者头像
     * @param id 当前登录患者id
     * @param headImages 头像url
     * @return java.lang.String
     * @throws IOException IO异常
     */
    @Override
    public String changeAvatar(Integer id, MultipartFile headImages) throws IOException {
        //获取上传的文件名称，并结合存放路径，构建新的文件名称
        String originalFilename = headImages.getOriginalFilename();
        //获取文件后缀名
        assert originalFilename != null;
        String[] split = originalFilename.split("\\.");
        //生成随机
        String s = UUID.randomUUID().toString();
        //拼接
        String fileName = s+"."+split[1];
        System.out.println(fileName);
        //oos 上传
        OSSUploadUtils.uploadFile(bucket,headImages.getInputStream(),fileName,endpoint, accessKeyId, accessKeySecret);
        //oss url
        String url=endpoint.replaceFirst("http://","http://"+bucket +".")+"/"+fileName;
        patientMapper.changeAvatar(id,url);
        //返回
        return url;
    }

    /**
     * 修改余额
     * @param patientId 患者id
     * @param payMoney 支付金额
     * @return int
     */
    @Override
    public int updatePatientBalance(int patientId, Double payMoney) {
        return  patientMapper.updatePatientBalance(patientId,payMoney);
    }

    /**
     * 计算健康分数
     * @author 1804A-TeamOne
     * @date 2020-12-17 16:57
     * @param healthTestRequest 健康测试请求类
     * @return com.itcanteen.medical.patient.request.HealthTestRequest
     */
    @Override
    public HealthTestRequest healthTest(HealthTestRequest healthTestRequest) {

        //生活长度
        int lifeLength = healthTestRequest.getLife().split("_").length;
        //食物长度
        int footLength = healthTestRequest.getFood().split("_").length;
        //身体状况
        int illnessLength = healthTestRequest.getIllness().split("_").length;

        int score = BASE_SCORE;
        //最终分数
        score += lifeLength*4+footLength*4-illnessLength*4;
        healthTestRequest.setScore(score);

        return healthTestRequest;
    }

}
